package com.jet.merchant.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jet.core.enums.CommonStatus;
import com.jet.core.enums.IEnum;
import com.jet.core.exception.CustomException;
import com.jet.core.model.vo.PageVo;
import com.jet.core.result.ResultCode;
import com.jet.core.utils.IdUtil;
import com.jet.merchant.domain.dto.PowerCreateDto;
import com.jet.merchant.domain.dto.RoleDto;
import com.jet.merchant.domain.dto.RoleResourceMapDto;
import com.jet.merchant.domain.entity.ClerkAccountRoleMap;
import com.jet.merchant.domain.entity.ClerkRole;
import com.jet.merchant.domain.entity.ClerkRoleResourceMap;
import com.jet.merchant.domain.enums.ResourceTypeConst;
import com.jet.merchant.domain.enums.RoleDefaultConst;
import com.jet.merchant.domain.query.RolePageQuery;
import com.jet.merchant.domain.vo.PowerVo;
import com.jet.merchant.domain.vo.ResourceVo;
import com.jet.merchant.domain.vo.RoleVo;
import com.jet.merchant.mapper.ClerkRoleMapper;
import com.jet.merchant.service.IClerkAccountRoleMapService;
import com.jet.merchant.service.IClerkResourceService;
import com.jet.merchant.service.IClerkRoleResourceMapService;
import com.jet.merchant.service.IClerkRoleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestParam;

import javax.management.relation.Role;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-02-25
 */
@Service
public class ClerkRoleServiceImpl extends ServiceImpl<ClerkRoleMapper, ClerkRole> implements IClerkRoleService {

    private final IClerkAccountRoleMapService clerkAccountRoleMapService;
    private final IClerkResourceService clerkResourceService;
    private final IClerkRoleResourceMapService clerkRoleResourceMapService;

    public ClerkRoleServiceImpl(IClerkAccountRoleMapService clerkAccountRoleMapService, IClerkResourceService clerkResourceService, IClerkRoleResourceMapService clerkRoleResourceMapService) {
        this.clerkAccountRoleMapService = clerkAccountRoleMapService;
        this.clerkResourceService = clerkResourceService;
        this.clerkRoleResourceMapService = clerkRoleResourceMapService;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(long merchantNo, RoleDto dto) {
        ClerkRole entity = new ClerkRole();
        entity.setId(IdUtil.generateLower());
        entity.setMerchantNo(merchantNo);
        entity.setName(dto.getName());
        entity.setCreateTime(LocalDateTime.now());
        entity.setUpdateTime(LocalDateTime.now());
        entity.setType(dto.getType());
        entity.setDefaultStatus(RoleDefaultConst.DEFAULT);
        entity.setStatus(CommonStatus.ENABLED.getCode());
        entity.setRemark(dto.getRemark());
        super.save(entity);
        powerCreate(merchantNo, entity.getId(), dto.getPowers());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(long merchantNo, String id, RoleDto dto) {
        ClerkRole entity = super.getById(id);
        if (entity == null) {
            throw new CustomException(ResultCode.BAD_REQUEST, "角色不存在");
        }
        entity.setRemark(dto.getRemark());
        entity.setType(dto.getType());
        entity.setUpdateTime(LocalDateTime.now());
        super.updateById(entity);
        powerCreate(merchantNo, entity.getId(), dto.getPowers());
    }

    /**
     * 设置商户注册默认使用的角色
     */

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editDefaultStatus(String id) {
        Wrapper<ClerkRole> wrapper = new LambdaQueryWrapper<>(ClerkRole.class)
                .eq(ClerkRole::getMerchantNo, 0)
                .eq(ClerkRole::getDefaultStatus, RoleDefaultConst.MERCHANT_DEFAULT);

        ClerkRole entity = new ClerkRole();
        entity.setDefaultStatus(RoleDefaultConst.DEFAULT);
        super.update(entity, wrapper);

        Wrapper<ClerkRole> defaultWrapper = new LambdaQueryWrapper<>(ClerkRole.class)
                .eq(ClerkRole::getMerchantNo, 0)
                .eq(ClerkRole::getId, id);

        ClerkRole defaultEntity = new ClerkRole();
        entity.setDefaultStatus(RoleDefaultConst.MERCHANT_DEFAULT);
        super.update(defaultEntity, defaultWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editStatus(long merchantNo, String id, int status) {
        if (IEnum.getByCode(status, CommonStatus.class) == null) {
            throw new CustomException("修改状态错误");
        }

        ClerkRole role = super.getById(id);
        if (role == null) {
            throw new CustomException("角色信息错误");
        }
        if (merchantNo == 0 && role.getDefaultStatus() == RoleDefaultConst.MERCHANT_DEFAULT) {
            throw new CustomException("为默认注册使用角色，不允许修改");
        }
        ClerkRole entity = new ClerkRole();
        entity.setStatus(status);
        entity.setId(id);
        super.updateById(entity);
    }

    @Override
    public void delete(long merchantNo, String id) {
        ClerkRole entity = super.getById(id);
        if (entity == null) {
            throw new CustomException(ResultCode.BAD_REQUEST, "角色不存在");
        }
        if (entity.getMerchantNo() == 0) {
            throw new CustomException(ResultCode.BAD_REQUEST, "删除失败，公共角色不允许删除");
        }
        List<ClerkAccountRoleMap> list = clerkAccountRoleMapService.findAllByRoleId(id);
        if (!CollectionUtils.isEmpty(list)) {
            throw new CustomException(ResultCode.BAD_REQUEST, "有正在使用的权限信息，不允许修改");
        }
        clerkRoleResourceMapService.deleteByRoleId(id);
        super.removeById(id);
    }

    @Override
    public PageVo<RoleVo> page(long merchantNo, RolePageQuery query) {
        List<Long> merchantNos = new ArrayList<>();
        merchantNos.add(0L);
        merchantNos.add(merchantNo);
        Page<ClerkRole> tempQuery = new Page<>(query.getPageIndex(), query.getPageSize());
        Wrapper<ClerkRole> wrapper = new LambdaQueryWrapper<>(ClerkRole.class)
                .in(ClerkRole::getMerchantNo, merchantNos)
                .orderByDesc(ClerkRole::getCreateTime);
        IPage<ClerkRole> page = super.page(tempQuery, wrapper);
        if (CollUtil.isEmpty(page.getRecords())) {
            return PageVo.result();
        }
        List<RoleVo> vos = page.getRecords().stream().map(role -> {
            RoleVo vo = new RoleVo();
            BeanUtils.copyProperties(role, vo);
            return vo;
        }).collect(Collectors.toList());
        return PageVo.result(page, vos);
    }

    @Override
    public List<ClerkRole> list(long merchantNo) {
        List<Long> merchantNos = new ArrayList<>();
        merchantNos.add(0L);
        merchantNos.add(merchantNo);
        Wrapper<ClerkRole> wrapper = new LambdaQueryWrapper<>(ClerkRole.class)
                .in(ClerkRole::getMerchantNo, merchantNos);
        return super.list(wrapper);
    }

    /**
     * 获取默认角色
     *
     * @return
     */

    @Override
    public ClerkRole findByDefaultStatus(long merchantNo, int defaultStatus) {
        List<Long> merchantNos = new ArrayList<>();
        merchantNos.add(0L);
        merchantNos.add(merchantNo);
        Wrapper<ClerkRole> wrapper = new LambdaQueryWrapper<>(ClerkRole.class)
                .in(ClerkRole::getMerchantNo, merchantNos)
                .eq(ClerkRole::getDefaultStatus, defaultStatus);
        return super.getOne(wrapper);
    }


    @Override
    public void powerCreate(long merchantNo, String roleId, List<PowerCreateDto> dtos) {
        clerkRoleResourceMapService.deleteByRoleId(roleId);
        getChildren(roleId, dtos);
    }

    private void getChildren(String roleId, List<PowerCreateDto> children) {
        for (PowerCreateDto dto : children) {
            this.powerMenuCreate(roleId, dto.getId());
            ResourceVo resourceVo = clerkResourceService.info(dto.getId());
            if (resourceVo != null && resourceVo.getType() == ResourceTypeConst.BUTTON
                    && StrUtil.isNotBlank(resourceVo.getDirectoryId())) {
                List<String> directoryIds = Stream.of(resourceVo.getDirectoryId()
                        .split(",")).collect(Collectors.toList());
                directoryIds.forEach(x -> powerMenuCreate(roleId, x));
            }

            if (CollUtil.isNotEmpty(dto.getChildren())) {
                getChildren(roleId, dto.getChildren());
            }
        }
    }


    @Override
    public void powerMenuCreate(String roleId, String resourceId) throws CustomException {
        RoleResourceMapDto entity = new RoleResourceMapDto();
        entity.setRoleId(roleId);
        entity.setResourceId(resourceId);
        clerkRoleResourceMapService.save(entity);
    }


    @Override
    public List<PowerVo> powerMenu(@RequestParam long merchantNo,
                                   @RequestParam String accountId) {
        List<ResourceVo> resources = clerkResourceService.findAll();
        if (CollectionUtils.isEmpty(resources)) {
            return Collections.emptyList();
        }
        resources = resources.stream().filter(x -> x.getType() != ResourceTypeConst.LIST).collect(Collectors.toList());
        return getChildResource("0", resources);
    }

    private List<PowerVo> getChildResource(String id, List<ResourceVo> resources) {
        return resources.stream()
                .filter(x -> id.equals(x.getPid()))
                .sorted(Comparator.comparing(ResourceVo::getSort))
                .map(x -> {
                    PowerVo vo = new PowerVo();
                    vo.setId(x.getId());
                    vo.setName(x.getName());
                    vo.setTitle(x.getTitle());
                    vo.setType(x.getType());
                    vo.setChildren(getChildResource(x.getId(), resources));
                    return vo;
                }).collect(Collectors.toList());
    }


    @Override
    public List<String> powerMenuChecked(long merchantNo, String roleId, String accountId) {
        List<ClerkRoleResourceMap> menus = clerkRoleResourceMapService.findAllByRoleId(roleId);
        if (CollUtil.isEmpty(menus)) {
            return null;
        }
        List<String> resourceIds = menus.stream().map(ClerkRoleResourceMap::getResourceId).collect(Collectors.toList());
        List<ResourceVo> resources = clerkResourceService.findAllByIds(resourceIds);
        resources = resources.stream().filter(x -> x.getType() != ResourceTypeConst.LIST).collect(Collectors.toList());
        return getChildResource1("0", resources);
    }

    private List<String> getChildResource1(String id, List<ResourceVo> resources) {
        List<String> list = new ArrayList<>();
        resources.forEach(x -> {
            if (resources.stream().noneMatch(y -> x.getId().equals(y.getPid()))) {
                list.add(x.getId());
            }
        });
        return list;
    }
}
